package com.such.kit.bean;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.beanutils.BeanUtils;
import org.openjdk.jol.info.GraphLayout;
import com.such.kit.Callable;
import com.such.kit.Logger;
import com.such.kit.bean.bean.CompareResult;
import com.such.kit.cache.CacheCommons;
import com.such.kit.file.FileCommons;
import com.such.kit.file.exception.FileExistException;
import com.such.kit.stream.StreamCommons;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;

/**
 * @author SUCH
 * <pre>
 * 处理 JavaBean 的通用工具类
 * 
 * 当前版本基于 Apache Commons BeanUtils 重新了部分方法
 * </pre>
 */
public class BeanCommons {

	private static String classCache = CacheCommons.buildCacheName(BeanCommons.class, "class");
	private static String gsModeGet = "get";
	private static String gsModeSet = "set";

	/**
	 * <pre>
	 * 查找类
	 * </pre>
	 * @param className 类名
	 * @return 类
	 * @throws Exception
	 */
	public static <T> Class<T> getClass(final String className) 
			throws Exception {
		return CacheCommons.get(classCache, className, new Callable<String, Class<T>>() {
			@Override
			public Class<T> call(String cacheName) throws Exception {
				return (Class<T>) Class.forName(className);
			}
		});
	}

	/**
	 * <pre>
	 * 获取类名
	 * </pre>
	 * @param clazz 类
	 * @return 类名
	 */
	public static String getName(Class<?> clazz) {
		return clazz.getName();
	}

	/**
	 * <pre>
	 * 获取短类名
	 * </pre>
	 * @param clazz 类
	 * @return 短类名
	 */
	public static String getSimpleName(Class<?> clazz) {
		return clazz.getSimpleName();
	}

	/**
	 * <pre>
	 * 调用指定的公开方法
	 * 
	 * [警告] 此方法只能调用公开方法
	 * </pre>
	 * @param bean 实例
	 * @param name 方法名称
	 * @param types 方法参数类型集
	 * @param args 方法参数值集
	 * @return 执行结果集
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static <T> T callMethod(Object bean, String name, Class<?>[] types, Object[] args) 
			throws SecurityException, NoSuchMethodException, IllegalArgumentException, 
			IllegalAccessException, InvocationTargetException {
		T value = null;
		if (ValidateCommons.isNotEmpty(bean)) {
			Class<?> clazz = bean.getClass();
			Method method = clazz.getMethod(name, types);
			Object object = method.invoke(bean, args);
			if (ValidateCommons.isNotEmpty(object)) {
				value = (T) object;
			}
		}
		return value;
	}

	/**
	 * <pre>
	 * 调用指定的公开静态方法
	 * 
	 * [警告] 此方法只能调用公开静态方法
	 * </pre>
	 * @param clazz 类
	 * @param name 方法名称
	 * @param types 方法参数类型集
	 * @param args 方法参数值集
	 * @return 执行结果集
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static <T> T callMethod(Class<?> clazz, String name, Class<?>[] types, Object[] args) 
			throws SecurityException, NoSuchMethodException, IllegalArgumentException, 
			IllegalAccessException, InvocationTargetException {
		Method method = clazz.getMethod(name, types);
		Object object = method.invoke (null, args);
		T value = null;
		if (ValidateCommons.isNotEmpty(object)) {
			value = (T) object;
		}
		return value;
	}

	/**
	 * <pre>
	 * 取标准 JavaBean 指定属性的值
	 * 
	 * [警告] 指定属性需拥有 get、set 方法
	 * </pre>
	 * @param bean 实例
	 * @param name 属性名称
	 * @return 属性值
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static <T> T getValue(Object bean, String name) 
			throws SecurityException, NoSuchMethodException, IllegalArgumentException, 
			IllegalAccessException, InvocationTargetException {
		T value = null;
		if (ValidateCommons.isNotEmpty(bean) && ValidateCommons.isNotEmpty(name)) {
			Class<?> clazz = bean.getClass();
			Method method = getGSMethod(gsModeGet, clazz, name, null);
			Object object = method.invoke(bean);
			if (ValidateCommons.isNotEmpty(object)) {
				value = (T) object;
			}
		}
		return value;
	}

	/**
	 * <pre>
	 * 取类中指定的公开静态属性的值
	 * </pre>
	 * @param clazz 类
	 * @param name 属性名称
	 * @return 属性值
	 * @throws IllegalArgumentException
	 * @throws SecurityException
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 */
	public static <T> T getValue(Class<?> clazz, String name) 
			throws IllegalArgumentException, SecurityException, IllegalAccessException, 
			NoSuchFieldException {
		Field field = clazz.getField(name);
		Object object = field.get(null);
		T value = null;
		if (ValidateCommons.isNotEmpty(object)) {
			value = (T) object;
		}
		return value;
	}

	/**
	 * <pre>
	 * 取类中指定的私有属性的值
	 * </pre>
	 * @param bean 实例
	 * @param name 属性名称
	 * @return 属性值
	 * @throws NoSuchFieldException 
	 * @throws SecurityException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	public static <T> T getPrivateValue(Object bean, String name) 
			throws NoSuchFieldException, SecurityException, IllegalArgumentException, 
			IllegalAccessException {
		T value = null;
		if (ValidateCommons.isNotEmpty(bean) && ValidateCommons.isNotEmpty(name)) {
			Class<?> clazz = bean.getClass();
			Field field = clazz.getDeclaredField(name);
			field.setAccessible(true);
			Object object = field.get(bean);
			if (ValidateCommons.isNotEmpty(object)) {
				value = (T) object;
			}
		}
		return value;
	}

	/**
	 * <pre>
	 * 取类中指定的私有静态属性的值
	 * </pre>
	 * @param bean 实例
	 * @param name 属性名称
	 * @return 属性值
	 * @throws NoSuchFieldException 
	 * @throws SecurityException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	public static <T> T getPrivateValue(Class<?> clazz, String name) 
			throws NoSuchFieldException, SecurityException, IllegalArgumentException, 
			IllegalAccessException {
		Field field = clazz.getDeclaredField(name);
		field.setAccessible(true);
		Object object = field.get(null);
		T value = null;
		if (ValidateCommons.isNotEmpty(object)) {
			value = (T) object;
		}
		return value;
	}

	/**
	 * <pre>
	 * 为标准 JavaBean 指定属性赋值
	 * 
	 * [警告] 指定属性消需拥有 get、set 方法
	 * </pre>
	 * @param bean 实例
	 * @param name 属性名
	 * @param value 属性值
	 * @return 赋值后的实例
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static <T> T setValue(T bean, String name, Object value) 
			throws IllegalAccessException, InvocationTargetException {
		BeanUtils.setProperty(bean, name, value);
		return bean;
	}

	/**
	 * <pre>
	 * 为类中指定的公开静态属性赋值
	 * </pre>
	 * @param clazz 类
	 * @param name 属性名
	 * @param value 属性值
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 * @throws SecurityException
	 */
	public static void setValue(Class<?> clazz, String name, Object value) 
			throws IllegalArgumentException, IllegalAccessException, 
			NoSuchFieldException, SecurityException {
		clazz.getField(name).set(null, value);
	}

	/**
	 * <pre>
	 * 获取类中属性名称
	 * </pre>
	 * @param clazz 类
	 * @param atavistic 是否向父级递归 [true 为是]
	 * @param modifiers 声明类型范围 [参考 {@link Modifier Modifier.*}]
	 * @return 属性名称集
	 */
	public static List<String> getAttributeNames(Class<?> clazz, boolean atavistic, int... modifiers) {
		List<String> names = new ArrayList<String>();
		Field[] fields = clazz.getDeclaredFields();
		if (ValidateCommons.isNotEmpty(fields)) {
			Set<Integer> filter = new HashSet<Integer>();
			if (ValidateCommons.isNotEmpty(modifiers)) {
				for (int modifier : modifiers) {
					filter.add(modifier);
				}
			}
			for (Field field : fields) {
				if (ValidateCommons.isEmpty(filter) || filter.contains(field.getModifiers())) {
					names.add(field.getName());
				}
			}
		}
		if (atavistic) {
			Class<?> superclass = clazz.getSuperclass();
			if (!Object.class.equals(superclass)) {
				List<String> supernames = getAttributeNames(superclass, atavistic, modifiers);
				names.addAll(supernames);
			}
		}
		return names;
	}

	/**
	 * <pre>
	 * [参考 {@link #getAttributeNames(Class, boolean, int...)}]
	 * 
	 * atavistic 默认为 true
	 * </pre>
	 */
	public static List<String> getAttributeNames(Class<?> clazz, int... modifiers) {
		return getAttributeNames(clazz, true, modifiers);
	}

	/**
	 * <pre>
	 * [参考 {@link #getAttributeNames(Class, boolean, int...)}]
	 * 
	 * atavistic 默认为 true
	 * modifiers 默认为 {@link Modifier#PRIVATE 私有的}
	 * </pre>
	 */
	public static List<String> getAttributeNames(Class<?> clazz) {
		return getAttributeNames(clazz, true, Modifier.PRIVATE);
	}

	/**
	 * <pre>
	 * 获取类中属性类型
	 * </pre>
	 * @param clazz 类
	 * @param atavistic 是否向父级递归 [true 为是]
	 * @param modifiers 声明类型范围 [参考 {@link Modifier Modifier.*}]
	 * @return 属性类型集
	 */
	public static Map<String, Class<?>> getAttributeTypes(Class<?> clazz, boolean atavistic, int... modifiers) {
		Map<String, Class<?>> typeMap = new HashMap<String, Class<?>>();
		Field[] fields = clazz.getDeclaredFields();
		if (ValidateCommons.isNotEmpty(fields)) {
			Set<Integer> filter = new HashSet<Integer>();
			if (ValidateCommons.isNotEmpty(modifiers)) {
				for (int modifier : modifiers) {
					filter.add(modifier);
				}
			}
			for (Field field : fields) {
				if (ValidateCommons.isEmpty(filter) || filter.contains(field.getModifiers())) {
					typeMap.put(field.getName(), field.getType());
				}
			}
		}
		if (atavistic) {
			Class<?> superclass = clazz.getSuperclass();
			if (!Object.class.equals(superclass)) {
				Map<String, Class<?>> supertypeMap = getAttributeTypes(superclass, atavistic, modifiers);
				typeMap.putAll(supertypeMap);
			}
		}
		return typeMap;
	}


	/**
	 * <pre>
	 * [参考 {@link #getAttributeTypes(Class, boolean, int...)}]
	 * 
	 * atavistic 默认为 true
	 * </pre>
	 */
	public static Map<String, Class<?>> getAttributeTypes(Class<?> clazz, int... modifiers) {
		return getAttributeTypes(clazz, true, modifiers);
	}

	/**
	 * <pre>
	 * [参考 {@link #getAttributeTypes(Class, boolean, int...)}]
	 * 
	 * atavistic 默认为 true
	 * modifiers 默认为 {@link Modifier#PRIVATE 私有的}
	 * </pre>
	 */
	public static Map<String, Class<?>> getAttributeTypes(Class<?> clazz) {
		return getAttributeTypes(clazz, true, Modifier.PRIVATE);
	}

	/**
	 * <pre>
	 * 获取类中属性泛型类型
	 * </pre>
	 * @param clazz 类
	 * @param atavistic 是否向父级递归 [true 为是]
	 * @param modifiers 声明类型范围 [参考 {@link Modifier Modifier.*}]
	 * @return 属性泛型类型集
	 */
	public static Map<String, Type> getAttributeGenericityTypes(Class<?> clazz, boolean atavistic, int... modifiers) {
		Map<String, Type> typeMap = new HashMap<String, Type>();
		Field[] fields = clazz.getDeclaredFields();
		if (ValidateCommons.isNotEmpty(fields)) {
			Set<Integer> filter = new HashSet<Integer>();
			if (ValidateCommons.isNotEmpty(modifiers)) {
				for (int modifier : modifiers) {
					filter.add(modifier);
				}
			}
			for (Field field : fields) {
				if (ValidateCommons.isEmpty(filter) || filter.contains(field.getModifiers())) {
					Type genericType = field.getGenericType();
					/*
					if (genericType instanceof ParameterizedType) {
						ParameterizedType pt = (ParameterizedType) genericType;
					}
					*/
					typeMap.put(field.getName(), genericType);
				}
			}
		}
		if (atavistic) {
			Class<?> superclass = clazz.getSuperclass();
			if (!Object.class.equals(superclass)) {
				Map<String, Class<?>> supertypeMap = getAttributeTypes(superclass, atavistic, modifiers);
				typeMap.putAll(supertypeMap);
			}
		}
		return typeMap;
	}

	/**
	 * <pre>
	 * [参考 {@link #getAttributeGenericityTypes(Class, boolean, int...)}]
	 * 
	 * atavistic 默认为 true
	 * </pre>
	 */
	public static Map<String, Type> getAttributeGenericityTypes(Class<?> clazz, int... modifiers) {
		return getAttributeGenericityTypes(clazz, true, modifiers);
	}

	/**
	 * <pre>
	 * [参考 {@link #getAttributeGenericityTypes(Class, boolean, int...)}]
	 * 
	 * atavistic 默认为 true
	 * modifiers 默认为 {@link Modifier#PRIVATE 私有的}
	 * </pre>
	 */
	public static Map<String, Type> getAttributeGenericityTypes(Class<?> clazz) {
		return getAttributeGenericityTypes(clazz, true, Modifier.PRIVATE);
	}

	/**
	 * <pre>
	 * 将标准 JavaBean 属性与值填充到 Map 中
	 * </pre>
	 * @param bean 实例
	 * @param names 指定需要处理的属性
	 * @return 填充后的 Map
	 * @throws SecurityException
	 * @throws IllegalArgumentException
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static <T> Map<String, T> toMap(Object bean, String... names) 
			throws SecurityException, IllegalArgumentException, NoSuchMethodException, 
			IllegalAccessException, InvocationTargetException {
		Map<String, T> beanMap = new HashMap<String, T>();
		if (ValidateCommons.isNotEmpty(names)) {
			for (String name : names) {
				T value = getValue(bean, name);
				beanMap.put(name, value);
			}
		}
		return beanMap;
	}

	/**
	 * <pre>
	 * [参考 {@link #toMap(Object, String...)}]
	 * 
	 * names 默认为所有私有属性
	 * </pre>
	 */
	public static <T> Map<String, T> toMap(Object bean) 
			throws SecurityException, IllegalArgumentException, NoSuchMethodException, 
			IllegalAccessException, InvocationTargetException {
		List<String> names = getAttributeNames(bean.getClass());
		return toMap(bean, names.toArray(new String[0]));
	}

	/**
	 * <pre>
	 * 将 Map 中的键值对填充到标准 JavaBean 中
	 * 键对应标准 JavaBean 的属性名称，键值为其值
	 * </pre>
	 * @param beanMap Map
	 * @param clazz 类
	 * @param names 指定需要处理的属性
	 * @return 填充后的实例
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws SecurityException
	 * @throws IllegalArgumentException
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 */
	public static <T> T toBean(Map<String, ?> beanMap, Class<T> clazz, String... names) 
			throws InstantiationException, IllegalAccessException, SecurityException, 
			IllegalArgumentException, NoSuchMethodException, InvocationTargetException {
		T bean = clazz.newInstance();
		if (ValidateCommons.isNotEmpty(names)) {
			for (String name : names) {
				Object value = beanMap.get(name);
				if (ValidateCommons.isNotEmpty(value)) {
					setValue(bean, name, value);
				}
			}
		}
		return bean;
	}

	/**
	 * <pre>
	 * [参考 {@link #toBean(Map, Class, String...)}]
	 * 
	 * names 默认为所有私有属性
	 * </pre>
	 */
	public static <T> T toBean(Map<String, ?> beanMap, Class<T> clazz) 
			throws InstantiationException, IllegalAccessException, SecurityException, 
			IllegalArgumentException, NoSuchMethodException, InvocationTargetException {
		List<String> names = getAttributeNames(clazz);
		return toBean(beanMap, clazz, names.toArray(new String[0]));
	}

	/**
	 * <pre>
	 * 序列化对象
	 * </pre>
	 * @param bean 实例
	 * @return 序列化二进制流
	 * @throws IOException
	 */
	public static InputStream serialization(Serializable bean) 
			throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ObjectOutputStream outObj = null;
		try {
			outObj = new ObjectOutputStream(out);
			outObj.flush();
			outObj.writeObject(bean);
		} finally {
			StreamCommons.close(outObj);
		}
		return new ByteArrayInputStream(out.toByteArray());
	}

	/**
	 * <pre>
	 * 反序列化对象
	 * </pre>
	 * @param in 序列化二进制流
	 * @return 实例
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public static <T extends Serializable> T unSerialization(InputStream in) 
			throws IOException, ClassNotFoundException {
		T bean = null;
		ObjectInputStream objIn = null;
		try {
			objIn = new ObjectInputStream(in);
			Object object = objIn.readObject();
			if (ValidateCommons.isNotEmpty(object)) {
				bean = (T) object;
			}
		} finally {
			StreamCommons.close(objIn);
		}
		return bean;
	}

	/**
	 * <pre>
	 * 序列化对象二进制流到指定文件
	 * </pre>
	 * @param bean 实例
	 * @param targetPath 目标文件绝对路径
	 * @throws FileExistException
	 * @throws IOException
	 */
	public static void serialization(Serializable bean, String targetPath) 
			throws FileExistException, IOException {
		targetPath = FileCommons.changeCompatSeparator(targetPath);
		File targetFile = new File(targetPath);
		if (targetFile.exists()) {
			throw new FileExistException(targetPath);
		}
		FileCommons.createFolder(FileCommons.cutLastPathNode(targetPath));
		ObjectOutputStream outObj = null;
		try {
			outObj = new ObjectOutputStream(new FileOutputStream(targetFile));
			outObj.flush();
			outObj.writeObject(bean);
		} finally {
			StreamCommons.close(outObj);
		}
	}

	/**
	 * <pre>
	 * 将序列化二进制流文件反序列化对象
	 * </pre>
	 * @param filePath 文件绝对路径
	 * @return 实例
	 * @throws ClassNotFoundException
	 * @throws IOException
	 */
	public static <T extends Serializable> T unSerialization(String filePath) 
			throws ClassNotFoundException, IOException {
		filePath = FileCommons.changeCompatSeparator(filePath);
		File file = new File(filePath);
		T obj = null;
		if (file.exists()) {
			ObjectInputStream objIn = null;
			try {
				objIn = new ObjectInputStream(new FileInputStream(file));
				Object object = objIn.readObject();
				if (ValidateCommons.isNotEmpty(object)) {
					obj = (T) object;
				}
			} finally {
				StreamCommons.close(objIn);
			}
		}
		return obj;
	}

	/**
	 * <pre>
	 * 序列化对象为 xml 字符串
	 * </pre>
	 * @param bean 实例
	 * @param charset 字符集
	 * @return xml 字符串
	 * @throws UnsupportedEncodingException
	 */
	public static String serializationToXml(Serializable bean, String charset) 
			throws UnsupportedEncodingException {
		String xml = "";
		XMLEncoder encoder = null;
		try {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			encoder = new XMLEncoder(out);
			encoder.writeObject(bean);
			encoder.flush();
			if (ValidateCommons.isEmpty(charset)) {
				xml = out.toString();
			} else {
				xml = out.toString(charset);
			}
		} finally {
			if (ValidateCommons.isNotEmpty(encoder)) {
				encoder.close();
			}
		}
		return xml;
	}

	/**
	 * <pre>
	 * [参考 {@link #serializationToXml(Serializable, String)}]
	 * 
	 * charset 为系统默认字符集
	 * </pre>
	 */
	public static String serializationToXml(Serializable bean) 
			throws Exception {
		return serializationToXml(bean, null);
	}

	/**
	 * <pre>
	 * 从 xml 字符串反序列化对象
	 * </pre>
	 * @param xml 序列化 xml 字符串
	 * @param charset 字符集
	 * @return 实例
	 * @throws UnsupportedEncodingException
	 */
	public static <T extends Serializable> T unSerializationFromXml(String xml, String charset) 
			throws UnsupportedEncodingException {
		T bean = null;
		XMLDecoder decoder = null;
		try {
			byte[] bytes = null;
			if (ValidateCommons.isEmpty(charset)) {
				bytes = xml.getBytes();
			} else {
				bytes = xml.getBytes(charset);
			}
			decoder = new XMLDecoder(new ByteArrayInputStream(bytes));
			Object object = decoder.readObject();
			if (ValidateCommons.isNotEmpty(object)) {
				bean = (T) object;
			}
		} finally {
			if (ValidateCommons.isNotEmpty(decoder)) {
				decoder.close();
			}
		}
		return bean;
	}

	/**
	 * <pre>
	 * [参考 {@link #unSerializationFromXml(String, String)}]
	 * 
	 * charset 为系统默认字符集
	 * </pre>
	 */
	public static <T extends Serializable> T unSerializationFromXml(String xml) 
			throws Exception {
		return unSerializationFromXml(xml, null);
	}

	/**
	 * <pre>
	 * 比较标准 JavaBean 差异
	 * </pre>
	 * @param bean1 实例 1
	 * @param bean2 实例 2
	 * @param keyAttributes 关键字段，原则上可以用于区分 bean 的唯一性，既二个 bean 从业务上是否是一条数据
	 * @return 对比结果
	 * @throws SecurityException
	 * @throws IllegalArgumentException
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static <T> CompareResult<T> compare(T bean1, T bean2, List<String> keyAttributes) 
			throws SecurityException, IllegalArgumentException, NoSuchMethodException, 
			IllegalAccessException, InvocationTargetException {
		CompareResult<T> compareResult = null;
		if (ValidateCommons.isNotEmpty(bean1) && ValidateCommons.isNotEmpty(bean2)) {
			compareResult = new CompareResult<T>(bean1, bean2, keyAttributes);
			List<Object> bean1KeyValues = new ArrayList<Object>();
			List<Object> bean2KeyValues = new ArrayList<Object>();
			List<String> differences = new ArrayList<String>();
			String same = null;
			Set<String> keyChecker = null;
			if (ValidateCommons.isEmpty(keyAttributes)) {
				same = CompareResult.SAME_UNKNOWN;
				keyChecker = new HashSet<String>();
			} else {
				same = CompareResult.SAME_NO;
				keyChecker = new HashSet<String>(keyAttributes);
			}
			for (String attribute : compareResult.getAttributes()) {
				Object value1 = compareResult.getBean1Value(attribute);
				Object value2 = compareResult.getBean2Value(attribute);
				if (!value1.equals(value2)) {
					differences.add(attribute);
				}
				if (keyChecker.contains(attribute)) {
					bean1KeyValues.add(value1);
					bean2KeyValues.add(value2);
				}
			}
			if (ValidateCommons.isNotEmpty(bean1KeyValues) && ValidateCommons.isNotEmpty(bean2KeyValues) && bean1KeyValues.equals(bean2KeyValues)) {
				same = CompareResult.SAME_YES;
			}
			compareResult.setResult(same, differences);
		}
		return compareResult;
	}

	/**
	 * <pre>
	 * 拷贝标准 JavaBean 中的属性
	 * 将属性名相同的属性从 from 拷贝到 to 中
	 * </pre>
	 * @param from 来源实例
	 * @param to 目标实例
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static void copy(Object from, Object to) 
			throws IllegalAccessException, InvocationTargetException {
		BeanUtils.copyProperties(to, from);
	}

	/**
	 * <pre>
	 * 基于属性拷贝的通用对象克隆
	 * </pre>
	 * @param bean 对象
	 * @return 克隆对象
	 */
	public static <T> T clone(T bean) 
			throws IllegalAccessException, InstantiationException, 
			InvocationTargetException, NoSuchMethodException {
		return (T) BeanUtils.cloneBean(bean);
	}

	/**
	 * <pre>
	 * 基于序列化的通用对象克隆
	 * 理论上来说，此方法可以处理更复杂的对象
	 * </pre>
	 * @param bean 对象
	 * @return 克隆对象
	 */
	public static <T extends Serializable> T cloneBySerializable(T bean) {
		T cloneBean = null;
		try {
			InputStream in = serialization(bean);
			cloneBean = unSerialization(in);
		} catch (IOException e) {
			Logger.error(BeanCommons.class, "clone（序列化）对象异常", e);
		} catch (ClassNotFoundException e) {
			Logger.error(BeanCommons.class, "clone（序列化）对象异常", e);
		}
		return cloneBean;
	}

	/**
	 * <pre>
	 * 计算对象集占用内存的大小
	 * 此方法依赖 jol-core 包
	 * 
	 * 单位 byte（1024byte = 1kb）
	 * </pre>
	 * @param objs 对象集
	 * @return 占用内存的大小
	 */
	public static long sizeOf(Object... objs) {
		return GraphLayout.parseInstance(objs).totalSize();
	}

	private static Method getGSMethod(String gsMode, Class<?> clazz, String name, Class<?> valueClass) 
			throws SecurityException, NoSuchMethodException {
		Set<String> filter = new HashSet<String>();
		if (gsModeGet.equals(gsMode)) {
			filter.add(StringCommons.toLowerCase(name));
			filter.add(StringCommons.toLowerCase(StringCommons.merger(gsModeGet, name)));
			filter.add(StringCommons.toLowerCase(StringCommons.merger("is", name)));
		} else if (gsModeSet.equals(gsMode)) {
			filter.add(StringCommons.toLowerCase(StringCommons.merger(gsModeSet, name)));
		}
		for (Method method : clazz.getMethods()) {
			String methodName = method.getName();
			String lowerMethodName = StringCommons.toLowerCase(methodName);
			if (filter.contains(lowerMethodName)) {
				if (ValidateCommons.isEmpty(valueClass)) {
					return clazz.getMethod(methodName);
				} else {
					return clazz.getMethod(methodName, valueClass);
				}
			}
		}
		throw new NoSuchMethodException(name);
	}

}
